package algorithms;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map.Entry;

import algorithms.models.FeatureBag;

import edu.uci.ics.jung.algorithms.scoring.PageRank;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.UndirectedSparseGraph;
import puppy.graph.AgeAggregator;

import puppy.graph.CreateGraphDirected;
import puppy.graph.CreateLM;
import puppy.graph.DeliciousEdge;
import puppy.graph.DeliciousEdgeTransformer;
import puppy.graph.DeliciousNode;
import puppy.graph.DeliciousNodeTransformer;
import puppy.graph.GraphExtractor;

import util.hashing.*;
import util.ranker.RankingService;

public class PageRankSuggestions implements RankingService{

	public CreateGraphDirected graph = null;
	CreateLM lm = null; 
	double query_total=0;
	
	DeliciousEdgeTransformer edge_transformer = null;
	DeliciousNodeTransformer node_transformer = null;
	AgeAggregator agg = null;
	public double epsilon=0.000001;
	
	public double alpha=0.0;
	public double gamma=0.0;
	public int level =2;
	
	public int max_iterations=5;

	public double n_gram_weight=2;
	public int mimimum_length_ngram=2;

	private int results_printed=0;

	private Float query_threshold_freq=3f;

	private int diversity_iterations=7;
	private int diversity_top=1;
	private int number_of_results=120;
	
	public Hashtable<String, FeatureBag> features= new Hashtable<String, FeatureBag>();
	public boolean featuresUpdate=true;
	
	
	public PageRankSuggestions(String path, String co_occur, String w_p, String d_p, String z_p, AgeAggregator agg,double alpha,int max_iterations, int level) {
		this.level=level;
		this.agg= agg;
		this.alpha=alpha;
		this.max_iterations=max_iterations;
		graph =new CreateGraphDirected(agg,w_p,d_p,z_p);
	
		graph.initGraph(path);
		
		graph.ages.clear();
		graph.ages=null;
		//graph.createGraph(path);
		
		//initLM(co_occur);
	}
	
	
	public void initLM(String path){
		if(path==null) return;
		
		lm = new CreateLM();
		lm.initLM(path);
	}
	
	
	public float calulateConditionalProb(Hashtable<String,Float>q){
		
		float p=0f;
		
		return p;
		
	}
	
	/*public Hashtable<String, Float> generatePossibleTokensNGram(String query_text) {
		Hashtable<String, Float> h = new Hashtable<String, Float>();

		String ngram = query_text.replace(" ", "_");
		String t[] = ngram.split("_");

		if (graph.nodes.containsKey(ngram)) {

			float prior =0;
			h.put(ngram, 0f);

		}

		HashSet<String> tokens = new HashSet<String>();
		for (int i = 0; i < t.length; i++) {

			
			if (i + 2 < t.length) {

				String m = t[i] + "_" + t[i + 1] + "_" + t[i + 2];
				if (graph.nodes.containsKey(m) && !tokens.contains(t[i]) && !tokens.contains(t[i+1]) &&!tokens.contains(t[i+2]) ) {

					tokens.add(t[i]);
					tokens.add(t[i+1]);
					tokens.add(t[i+2]);
					h.put(m, 0f);
				}

			}
			
			
			if (i + 1 < t.length) {

				String m = t[i] + "_" + t[i + 1];
				if (graph.nodes.containsKey(m) && !tokens.contains(t[i]) && !tokens.contains(t[i+1])) {

					tokens.add(t[i]);
					tokens.add(t[i+1]);
					
					h.put(m, 0f);
				}

			}
			if (graph.nodes.containsKey(t[i]) && !tokens.contains(t[i])) {
			
				tokens.add(t[i]);
				
				h.put(t[i], 0f);
			}

		}
		
		return h;
	}*/
	
	public ArrayList<Entry<String, Float>> performPageRankWithPriors(Hashtable<String,Float>q, String query, int limit){
		//create list of query n_gram phrases
		// star_wars --> star_wars_lego
		// star_wars_lego --> star_wars, star_wars_games, etc
		//q=generatePossibleTokensNGram(query);
	
		DeliciousNodeTransformer transformer = 
				new DeliciousNodeTransformer( q,agg,graph,lm,query, n_gram_weight,  mimimum_length_ngram);
	
		
	
		edge_transformer = 
				new DeliciousEdgeTransformer(agg);
		
		
		//RandomWalkWIthPriors<DeliciousNode, DeliciousEdge> ranker = 	
	//			new RandomWalkWIthPriors<DeliciousNode,DeliciousEdge>
	//	(graph.graph,edge_transformer,transformer, alpha);
	//	ranker.initModifiers(transformer, edge_transformer);
	
	
	//	System.exit(0);
		 
	/*	 RandomWalkMix<DeliciousNode, DeliciousEdge> ranker = 	
								new RandomWalkMix<DeliciousNode,DeliciousEdge>
						(graph.graph,edge_transformer,transformer, alpha);
		ranker.initModifiers(transformer, edge_transformer);
		 
		ranker.setTolerance(epsilon);
		
		ranker.acceptDisconnectedGraph(true);
		ranker.setMaxIterations(max_iterations);
		
		//ranker.setEdgeWeights(edge_weights)
		//System.out.println("Running page rank.." + "\t"+ q);
		ranker.evaluate();	
		
		Enumeration<String> nodes = graph.nodes.keys();
		Hashtable<String, Float> scores = new Hashtable<String, Float>();
		while (nodes.hasMoreElements()) {
			String node = nodes.nextElement();

			DeliciousNode no = graph.nodes.get(node);

			if (no.getName().equals("") || !no.isTag() || tagInQuery(no.getName(),query)) {
				
				continue;
			}
			
		
			double s = ranker.getVertexScore(no);
			scores.put(no.getName(), (float) s);

		

		}

		Iterator<Entry<String, Float>> tuples = Sorting.getTopN_Tuples(scores, false, 150);
		HashSet<String> temp = new HashSet<String>();
	
		int i=0;
		while (tuples.hasNext() ) {
			Entry<String, Float> t = tuples.next();
			
			if(!wasSuggestionsSeenBefore(temp,t.getKey())){
			i++;
		//	results.add(t);
			if(i<results_printed)
				System.out.println(query+ "\t"+ t.getKey() + "\t" + i +"\t" + t.getValue());
			temp.add(t.getKey());
			}
		}
		
		
		
		//clean modifiers
		tuples=null;
		temp.clear();
		temp=null;
		transformer.clean();
		transformer=null;
		
		
		q.clear();
		q=null;
		
		return null;
	}
	
	
	
	public ArrayList<Entry<String, Float>> performPageRanKAbsorving(Hashtable<String,Float>q, String query, int limit){
		
		
		
		//create list of query n_gram phrases
		// star_wars --> star_wars_lego
		// star_wars_lego --> star_wars, star_wars_games, etc
		//q=generatePossibleTokensNGram(query);

	
		DeliciousNodeTransformer transformer = 
				new DeliciousNodeTransformer(
				 q,agg,graph,lm,query, n_gram_weight,  mimimum_length_ngram);
	
	
	
		edge_transformer = 
				new DeliciousEdgeTransformer(agg);
		
		
		//RandomWalkWIthPriors<DeliciousNode, DeliciousEdge> ranker = 	
	//			new RandomWalkWIthPriors<DeliciousNode,DeliciousEdge>
	//	(graph.graph,edge_transformer,transformer, alpha);
	//	ranker.initModifiers(transformer, edge_transformer);
	
	
	//	System.exit(0);
		 
		/* RandomWalkAbsorving<DeliciousNode, DeliciousEdge> ranker = 	
								new RandomWalkAbsorving<DeliciousNode,DeliciousEdge>
						(graph.graph,edge_transformer,transformer, alpha);
		ranker.initModifiers(transformer, edge_transformer,q);
		 
		ranker.setTolerance(epsilon);
		
		ranker.acceptDisconnectedGraph(true);
		ranker.setMaxIterations(max_iterations);
		
		//ranker.setEdgeWeights(edge_weights)
		System.out.println("Running page rank.." + "\t"+ q);
		ranker.evaluate();	
		
		Enumeration<String> nodes = graph.nodes.keys();
		Hashtable<String, Float> scores = new Hashtable<String, Float>();
		while (nodes.hasMoreElements()) {
			String node = nodes.nextElement();

			DeliciousNode no = graph.nodes.get(node);

			if (no.getName().equals("") || !no.isTag() || tagInQuery(no.getName(),query)) {
				
				continue;
			}
			
		
			double s = ranker.getVertexScore(no);
			scores.put(no.getName(), (float) s);

		

		}

		Iterator<Entry<String, Float>> tuples = Sorting.getTopN_Tuples(scores, false, 150);
		HashSet<String> temp = new HashSet<String>();
	
		int i=0;
		while (tuples.hasNext() ) {
			Entry<String, Float> t = tuples.next();
			
			if(!wasSuggestionsSeenBefore(temp,t.getKey())){
			i++;
		//	results.add(t);
			if(i<results_printed)
				System.out.println(query+ "\t"+ t.getKey() + "\t" + i +"\t" + t.getValue());
			temp.add(t.getKey());
			}
		}
		
		
		
		//clean modifiers
		tuples=null;
		temp.clear();
		temp=null;
		transformer.clean();
		transformer=null;
		
		
		q.clear();
		q=null;*/
		
		return null;
	}
	
	
private boolean wasSuggestionsSeenBefore(HashSet<String> temp, String key) {
		// TODO Auto-generated method stub

		if(temp.contains(key+ "s")) return true;
		
		if(temp.contains(key.substring(0,key.length()-1))) return true;
	
		return false;
	}


public Hashtable<String,Float> rerankQueryRepresentation(Hashtable<String,Float>q, int limit){
	Hashtable<String,Float> r= new Hashtable<String,Float>();
	Iterator<String> temp = Sorting.getTopN(q, false,limit);
	while(temp.hasNext()){
		String key =temp.next();
		
		r.put(key, q.get(key));
	}
	return r;
	
}

	public Graph<DeliciousNode, DeliciousEdge>  extractSubGraph(UndirectedSparseGraph<DeliciousNode, DeliciousEdge> original,int level, Hashtable<String,Float>q)
	{
		
	HashSet<DeliciousNode> set = getQueryNodes(q);
	
	if(q.size()==0) {
		if(Constants.debug)
		System.out.println("Query set was zero");
		//System.exit(0);
	}
	
	//System.out.println(set.size());
	
	GraphExtractor extractor= new GraphExtractor(level,set);
	//Graph<DeliciousNode, DeliciousEdge> sub = 
	
	return extractor.extractGraph(original);
	
	}


	public HashSet<DeliciousNode> getQueryNodes( Hashtable<String,Float>q){
	
	HashSet<DeliciousNode> set= new HashSet<DeliciousNode>();
	Enumeration<String> keys = q.keys();
	while(keys.hasMoreElements()){
		
		
		String query = keys.nextElement();
		
		set.add(graph.nodes.get(query));
	}
	
	return set;
	
	}

	
	public ArrayList<Entry<String, Float>> performPageRank(Hashtable<String,Float>q,Hashtable<String,Float> q_topics, String query, int limit,HashSet<String> absorving_nodes){

	
	/**
	 * Change this back
	 * 
	 * 
	 */
	//q=rerankQueryRepresentation(q, 10);
		
	/*
	 * extract subgraph
	 * 
	 * 
	 */
	
	UndirectedSparseGraph<DeliciousNode, DeliciousEdge> subgraph=new UndirectedSparseGraph<DeliciousNode, DeliciousEdge> ();
	graph.subgraph=extractSubGraph(graph.graph1,level,q);
	//graph.subgraph=graph.graph1;
	
	
	//graph.subgraph=subgraph;
//	System.out.println(graph.graph1.getVertexCount() + "\t  subgraph size:" + graph.subgraph.getVertexCount());
	
	
	DeliciousNodeTransformer transformer = 
			new DeliciousNodeTransformer( q,q_topics,agg,graph, lm,query, n_gram_weight,  mimimum_length_ngram, absorving_nodes);
	
	
	
	DeliciousEdgeTransformer edge_transformer = new DeliciousEdgeTransformer(agg);
		
		
	//RandomWalkWIthPriors<DeliciousNode, DeliciousEdge> ranker = 	new RandomWalkWIthPriors<DeliciousNode,DeliciousEdge>(graph.subgraph,transformer, alpha);
	
		
	RandomWalkBackward<DeliciousNode, DeliciousEdge> ranker = 	new RandomWalkBackward<DeliciousNode,DeliciousEdge>(graph.subgraph,transformer, alpha,gamma);
		
		
	ranker.initModifiers(transformer, edge_transformer);
		
	ranker.setTolerance(epsilon);
		
	ranker.acceptDisconnectedGraph(true);
		ranker.setMaxIterations(max_iterations);
		
		//ranker.setEdgeWeights(edge_weights)
		//System.out.println("Running page rank..");
		ranker.evaluate();	
		
		Iterator<DeliciousNode> nodes_subgraph = graph.subgraph.getVertices().iterator();
		HashSet<String> borreme = new HashSet<String>();
 		Hashtable<String, Float> scores = new Hashtable<String, Float>();
 		
 		Iterator<DeliciousNode> temp = subgraph.getVertices().iterator();
 		Hashtable<String,ArrayList<Float>> temp1 = new Hashtable<String,ArrayList<Float>> ();
  		/* 
 		while(temp.hasNext()){
 			DeliciousNode t = temp.next();
 			
 			if(temp1.containsKey(t.getName())){
 				temp1.get(t.getName()).add(ranker.getVertexScore(t).floatValue());
 				
 			}else{
 				
 				ArrayList<Float> temp2 = new ArrayList<Float>();
 				temp2.add(ranker.getVertexScore(t).floatValue());
 				temp1.put(t.getName(), temp2);
 			}
 			
 		}
 			
 			
 		Enumeration<String> keys = temp1.keys();
 		
 		while(keys.hasMoreElements()){
 			
 			String key = keys.nextElement();
 			System.out.print(key + " scores: " );
 			ArrayList<Float> a = temp1.get(key);
 			for(int i =0; i <a.size(); i++){
 				
 				System.out.print(a.get(i)+"\t");
 			}
 			
 			System.out.println("");
 			
 		}*/
 		
 		
		while (nodes_subgraph.hasNext()) {
			
			DeliciousNode no =nodes_subgraph.next();
			if (no.getName().equals("") || !no.isTag() || tagInQuery(no.getName(),query) || no.getName().length()<2) {
				
				continue;
			}
		
			double s = ranker.getVertexScore(no);
			scores.put(no.getName(), (float) s);
		}
		
		Iterator<Entry<String, Float>> tuples = Sorting.getTopN_Tuples(scores, false, number_of_results);
		
		ArrayList<Entry<String, Float>> results  = new ArrayList<Entry<String, Float>>();
		
		int i=0;
		
		features = new Hashtable<String,FeatureBag>();
		while (tuples.hasNext() ) {
			Entry<String, Float> t = tuples.next();
			i++;
			results.add(t);
			
			if(featuresUpdate){
			addFeatures(t,transformer,i);
			
			}
			if(i<results_printed){
			//System.out.println(query+ "\t"+ t.getKey() + "\t" + i +"\t" + t.getValue());
			}
		}
		
		tuples=null;
		return results;
	}


	public void feedAbsorving(HashSet<String>absorving_nodes, ArrayList<Entry<String, Float>> first_iteration, ArrayList<Entry<String,Float>> results, HashSet<String>previous_results){
		
		
		
		for(int i =0 ; i <first_iteration.size() && i < diversity_top; i++){
			if(!previous_results.contains(first_iteration.get(i).getKey())){
				absorving_nodes.add(first_iteration.get(0).getKey());
				results.add(first_iteration.get(0));
				previous_results.add(first_iteration.get(0).getKey());
				first_iteration.remove(0);	
			}
		
		}
		
		
		
		
		
	}
	public ArrayList<Entry<String, Float>> performPageRankDiversity(Hashtable<String,Float>q,Hashtable<String,Float> q_topics, String query, int limit){


		ArrayList<Entry<String,Float>> results=new ArrayList<Entry<String,Float>>(); 
		HashSet<String>absorving_nodes= new HashSet<String>();
		ArrayList<Entry<String, Float>> first_iteration = performPageRank(q,q_topics,query,limit,null);

		HashSet<String> previous_results= new HashSet<String>();
		int total_nodes= first_iteration.size();

		feedAbsorving(absorving_nodes, first_iteration, results,previous_results);
		int i=0;
		first_iteration.clear();
		first_iteration=null;
		while(results.size()< total_nodes && i<diversity_iterations-1){
			first_iteration = performPageRank(q,q_topics,query,limit,absorving_nodes);
			feedAbsorving(absorving_nodes, first_iteration, results, previous_results);
			i++;

	}

		
		//add all the resting elements from the last iteration to results
		
		for (int j = 0; j < first_iteration.size(); j++) {
			if (!previous_results.contains(first_iteration.get(j).getKey())) {
				results.add(first_iteration.get(j));
			}
		}

		first_iteration.clear();
		first_iteration=null;
		
		
		System.out.println("Printing diversity final results--------------");
		for( i =0; i <results.size(); i++){
			
			System.out.println(results.get(i).getKey() + "\t"+ results.get(i).getValue());
			
			
		}
		System.out.println("End of diversity final results");

		return results;
	}

 public Hashtable<String,Float> reRankQueryTerms(Hashtable<String,Float> q, String query){
	 
	 Hashtable<String,Float> re = new Hashtable<String,Float>();
	 
	 Enumeration<String> keys = q.keys();
	 
	 while(keys.hasMoreElements()){
		 
		 
	 }
	 
	 return re;
	 
	 
 }
	private boolean tagInQuery(String name, String query) {
		// TODO Auto-generated method stub

		//example tag star   query star_wars
		
		query = query.replaceAll("_", " ");
		
		name = name.replaceAll("_", " ");
		
		String[] query_tokens = query.split(" ");
		String[] tag_tokens = name.split(" ");
		
		
		
		if(name.contains(query) && name.length()>query.length()) return false;
		
		if(query.equals(name)){
			
			
			return true;
	
		} 
		
		int matches=0;
		for(int i=0; i< tag_tokens.length; i++){
			
			for(int j=0; j<query_tokens.length; j++){
				
				if(tag_tokens[i].equals(query_tokens[j])){
				
					matches++;
					
				}
			}
		}
		
	
		if(matches>=tag_tokens.length) return true;
		
		return false;
	}
	
	

	public void performPageRank_temp() {

		PageRank<DeliciousNode, DeliciousEdge> ranker = new PageRank<DeliciousNode, DeliciousEdge>(
				graph.graph1, 0.15);
		
		
		ranker.acceptDisconnectedGraph(true);
		//ranker.setMaxIterations(1000);
		System.out.println(ranker.getIterations());
		//ranker.setEdgeWeights(edge_weights)
		System.out.println("Running page rank..");
		ranker.evaluate();	
		
		Enumeration<String> nodes = graph.nodes.keys();
		Hashtable<String, Float> scores = new Hashtable<String, Float>();
		while (nodes.hasMoreElements()) {
			String node = nodes.nextElement();

			DeliciousNode no = graph.nodes.get(node);

			if (no.getName().equals("")) {
				continue;
			}
			double s = ranker.getVertexScore(no);
			scores.put(no.getName(), (float) s);

			// System.out.println("The PageRank score of " + no + " is: " + );

		}

		Iterator<Entry<String, Float>> tuples = Sorting.sortHashNumericValues(
				scores, true);
		while (tuples.hasNext()) {
			Entry<String, Float> t = tuples.next();
			System.out.println(t.getKey() + "\t" + t.getValue());
		}

	}
	
	private void addFeatures(Entry<String, Float> t, DeliciousNodeTransformer transformer, int rank) {
		// TODO Auto-generated method stub
		
		String name = t.getKey();
		Float  score=t.getValue(); 
		
		DeliciousNode node = transformer.graph.nodes.get(name);
		
		
		FeatureBag f = new FeatureBag();
		
		if(features.containsKey(name)){
			 f = features.get(name);
			
		}
		
		f.score=Double.valueOf(score);
		f.rank=rank;
	
		f.q_lm= transformer.calculateQueryProb(node);
		
		f.kl=transformer.calculateKL(node);
		f.prob_kids= transformer.calculateForegroundProb(node);
		f.prob_adults= transformer.calculateBackgroundProb(node);
		features.put(name, f);
		
		
	}

	public static void main(String argvs[]) {

		String prefix = "/Users/sergioduarte/projects/data/graph/";

		String single_query="/Users/sergioduarte/projects/data/results/single_query/star_wars.txt";
		
		// String path =
		// "/media/sata__/data/delicious_graph/delicious_graphML_raw_ids_dmoz.txt";
		String path = prefix + "delicious_graphML_raw_ids_dmoz_youth.txt";
			
		
		String node_node = 	 path = prefix + "delicious_graphML_node_node_mix_kidsteens_simple.txt";
	//	AgeAggregator	agg= new AgeAggregator(true, true, true, true, false, false, true);
		
	//	PageRankSuggestions page = new PageRankSuggestions(path, node_node,agg);
	
	
		//page.performPageRankWithPriors();
		
		//page.performPageRank();
	}

	
	
	public Hashtable<String,Float> calculateQueryRatios(Hashtable<String, Float> q){
		
		Hashtable<String, Float> qq= new Hashtable<String, Float> ();
		
		
		Enumeration<String> keys = q.keys();
		float total=0.0f;
		while(keys.hasMoreElements()){
			String element  = keys.nextElement();
			
			if(element.contains("school")){
				
				
			//	System.out.println(graph.nodes.containsKey(element) + "---\t "+ element);
			}
			if(graph.nodes.containsKey(element)){
			total= total+ q.get(element);
			}
			
		}
		
		keys=q.keys();
		while(keys.hasMoreElements()){
			String tag= keys.nextElement();
			if(graph.nodes.containsKey(tag)){
				if (q.get(tag)>=query_threshold_freq){
			//	if(tag.equals("characterized")){System.out.println("aqui si estuvo characterizeds " );}
				qq.put(tag, q.get(tag)/total);		
				}
			}
			
			
		//	System.out.println(tag + "\t"+ qq.get(tag));
		}
//		System.out.println( q+"\t"+ qq);
		return qq;
	}	
	@Override
	public ArrayList<Entry<String, Float>> rankQuery(
			String query, Hashtable<String, Float> q, int limit) {
		
		
		Hashtable<String, Float> qq = calculateQueryRatios(q);
		// TODO Auto-generated method stub
	//	System.out.println(query + "\t" + qq);
		return performPageRank(qq,null,query,limit,null);
		
	
	//	return performPageRanKAbsorving(qq,query,limit);
		//return null;
	}

	@Override
	public ArrayList<Entry<String, Float>> rankQuery(String query, int limit) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ArrayList<Entry<String, Float>> rankQuery(String query,
			Hashtable<String, Float> q, Hashtable<String, Float> q_topics,
			int limit) {
		
		
		
		Hashtable<String, Float> qq = calculateQueryRatios(q);
		// TODO Auto-generated method stub
		if(Constants.debug)
		System.out.println(query + "\t" + qq);
	//	return performPageRankDiver(qq, q_topics,query,limit,null);
		
		return performPageRank(qq, q_topics,query,limit,null);
		
		
	}

}
